Add flags to assert lock/cache behavior to Cargo
authorAlex Crichton <alex@alexcrichton.com>
Tue, 28 Jun 2016 17:39:46 +0000 (10:39 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 19 Jul 2016 01:50:20 +0000 (18:50 -0700)
If a lock file is generated and some equivalent of `cargo fetch` is run then
Cargo shouldn't ever touch the network or modify `Cargo.lock` until any
`Cargo.toml` later changes, but this often wants to be asserted in some build
environments where it's a programmer error if Cargo attempts to access the
network.

The `--locked` flag added here will assert that `Cargo.lock` does not need to
change to proceed. That is, if `Cargo.lock` would be modified (as it
automatically is by default) this is turned into a hard error instead.

This `--frozen` will not only assert that `Cargo.lock` doesn't change (the same
behavior as `--locked`), but it will also will manually prevent Cargo from
touching the network by ensuring that all network requests return an error.

These flags can be used in environments where it is *expected* that no network
access happens (or no lockfile changes happen) because it has been pre-arranged
for Cargo to not happen. Examples of this include:

* CI for projects want to pass `--locked` to ensure that `Cargo.lock` is up to
  date before changes are checked in.
* Environments with vendored dependencies want to pass `--frozen` as touching
  the network indicates a programmer error that something wasn't vendored
  correctly.

A crucial property of these two flags is that **they do not change the behavior
of Cargo**. They are simply assertions at a few locations in Cargo to ensure
that actions expected to not happen indeed don't happen. Some documentation has
also been added to this effect.

Closes #2111

38 files changed:
src/bin/bench.rs
src/bin/build.rs
src/bin/cargo.rs
src/bin/clean.rs
src/bin/doc.rs
src/bin/fetch.rs
src/bin/generate_lockfile.rs
src/bin/git_checkout.rs
src/bin/init.rs
src/bin/install.rs
src/bin/login.rs
src/bin/metadata.rs
src/bin/new.rs
src/bin/owner.rs
src/bin/package.rs
src/bin/pkgid.rs
src/bin/publish.rs
src/bin/run.rs
src/bin/rustc.rs
src/bin/rustdoc.rs
src/bin/search.rs
src/bin/test.rs
src/bin/uninstall.rs
src/bin/update.rs
src/bin/verify_project.rs
src/bin/yank.rs
src/cargo/core/registry.rs
src/cargo/ops/lockfile.rs
src/cargo/ops/registry.rs
src/cargo/sources/git/utils.rs
src/cargo/sources/registry.rs
src/cargo/util/config.rs
src/doc/faq.md
tests/bad-config.rs
tests/build-auth.rs
tests/overrides.rs
tests/path.rs
tests/registry.rs

index 3db26741f4e3aa074c6ce938d9267002177cb53f..c7cf6b69332f6af55d8a0da03f29cc33716ac246 100644 (file)
@@ -20,6 +20,8 @@ pub struct Options {
     flag_example: Vec<String>,
     flag_test: Vec<String>,
     flag_bench: Vec<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
     arg_args: Vec<String>,
 }
 
@@ -46,6 +48,8 @@ Options:
     -v, --verbose ...            Use verbose output
     -q, --quiet                  No output printed to stdout
     --color WHEN                 Coloring: auto, always, never
+    --frozen                     Require Cargo.lock and cache are up to date
+    --locked                     Require Cargo.lock is up to date
 
 All of the trailing arguments are passed to the benchmark binaries generated
 for filtering benchmarks and generally providing options configuring how they
@@ -64,9 +68,11 @@ Compilation can be customized with the `bench` profile in the manifest.
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let ops = ops::TestOptions {
         no_run: options.flag_no_run,
index 3fc0fe32e6cf52b748a187ad424937cff72e5626..601344adf7c6ee4264e20c01fc68349e125815f5 100644 (file)
@@ -23,6 +23,8 @@ pub struct Options {
     flag_example: Vec<String>,
     flag_test: Vec<String>,
     flag_bench: Vec<String>,
+    flag_locked: bool,
+    flag_frozen: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -48,6 +50,8 @@ Options:
     -v, --verbose ...            Use verbose output
     -q, --quiet                  No output printed to stdout
     --color WHEN                 Coloring: auto, always, never
+    --frozen                     Require Cargo.lock and cache are up to date
+    --locked                     Require Cargo.lock is up to date
 
 If the --package argument is given, then SPEC is a package id specification
 which indicates which package should be built. If it is not given, then the
@@ -62,9 +66,11 @@ the --release flag will use the `release` profile instead.
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
     debug!("executing; cmd=cargo-build; args={:?}",
            env::args().collect::<Vec<_>>());
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
 
index cdd110f3cabb95458d0e465e3705c282c7562c70..d29a3cbb06feb9b2b946cef7fdf1a38b6b6d4372 100644 (file)
@@ -28,6 +28,8 @@ pub struct Flags {
     flag_explain: Option<String>,
     arg_command: String,
     arg_args: Vec<String>,
+    flag_locked: bool,
+    flag_frozen: bool,
 }
 
 const USAGE: &'static str = "
@@ -45,6 +47,8 @@ Options:
     -v, --verbose ...   Use verbose output
     -q, --quiet         No output printed to stdout
     --color WHEN        Coloring: auto, always, never
+    --frozen            Require Cargo.lock and cache are up to date
+    --locked            Require Cargo.lock is up to date
 
 Some common cargo commands are (see all commands with --list):
     build       Compile the current project
@@ -68,6 +72,16 @@ fn main() {
     execute_main_without_stdin(execute, true, USAGE)
 }
 
+macro_rules! configure_shell {
+    ($config:expr, $options:expr) => (
+        try!($config.configure($options.flag_verbose,
+                               $options.flag_quiet,
+                               &$options.flag_color,
+                               $options.flag_frozen,
+                               $options.flag_locked));
+    )
+}
+
 macro_rules! each_subcommand{
     ($mac:ident) => {
         $mac!(bench);
@@ -113,9 +127,11 @@ each_subcommand!(declare_mod);
   on this top-level information.
 */
 fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(flags.flag_verbose,
-                                flags.flag_quiet,
-                                &flags.flag_color));
+    try!(config.configure(flags.flag_verbose,
+                          flags.flag_quiet,
+                          &flags.flag_color,
+                          flags.flag_frozen,
+                          flags.flag_locked));
 
     init_git_transports(config);
     cargo::util::job::setup();
index 36ec7db1771edb59466bd1c7d75de7d0fb980973..c259e83c6f3d6bf6ebab3461ea9056d84bf17cbb 100644 (file)
@@ -14,6 +14,8 @@ pub struct Options {
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
     flag_release: bool,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -31,6 +33,8 @@ Options:
     -v, --verbose ...            Use verbose output
     -q, --quiet                  No output printed to stdout
     --color WHEN                 Coloring: auto, always, never
+    --frozen                     Require Cargo.lock and cache are up to date
+    --locked                     Require Cargo.lock is up to date
 
 If the --package argument is given, then SPEC is a package id specification
 which indicates which package's artifacts should be cleaned out. If it is not
@@ -40,9 +44,11 @@ and its format, see the `cargo help pkgid` command.
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
     debug!("executing; cmd=cargo-clean; args={:?}", env::args().collect::<Vec<_>>());
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
     let opts = ops::CleanOptions {
index 1c420def853ba89848e6e40d20fa66796f8d6ece..7f4fc2878e574cf9c480908002faa6fbd3b55edb 100644 (file)
@@ -19,6 +19,8 @@ pub struct Options {
     flag_package: Vec<String>,
     flag_lib: bool,
     flag_bin: Vec<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -43,6 +45,8 @@ Options:
     -v, --verbose ...            Use verbose output
     -q, --quiet                  No output printed to stdout
     --color WHEN                 Coloring: auto, always, never
+    --frozen                     Require Cargo.lock and cache are up to date
+    --locked                     Require Cargo.lock is up to date
 
 By default the documentation for the local package and all dependencies is
 built. The output is all placed in `target/doc` in rustdoc's usual format.
@@ -54,9 +58,11 @@ the `cargo help pkgid` command.
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
 
index 2870dc63a88378b8b4b8d40a7c9e4e462811020d..1a970b71f05594e63e0a97f6faa99227a0940e24 100644 (file)
@@ -9,6 +9,8 @@ pub struct Options {
     flag_verbose: u32,
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -23,6 +25,8 @@ Options:
     -v, --verbose ...        Use verbose output
     -q, --quiet              No output printed to stdout
     --color WHEN             Coloring: auto, always, never
+    --frozen                 Require Cargo.lock and cache are up to date
+    --locked                 Require Cargo.lock is up to date
 
 If a lockfile is available, this command will ensure that all of the git
 dependencies and/or registries dependencies are downloaded and locally
@@ -35,9 +39,11 @@ all updated.
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
     let ws = try!(Workspace::new(&root, config));
     try!(ops::fetch(&ws));
index a49930fd9ab1960aa70fb15042b2b73a859adf6f..36057c1bb6e7b8820e3326dabf3f2e4722ac9c0f 100644 (file)
@@ -11,6 +11,8 @@ pub struct Options {
     flag_verbose: u32,
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -25,13 +27,17 @@ Options:
     -v, --verbose ...        Use verbose output
     -q, --quiet              No output printed to stdout
     --color WHEN             Coloring: auto, always, never
+    --frozen                 Require Cargo.lock and cache are up to date
+    --locked                 Require Cargo.lock is up to date
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
     debug!("executing; cmd=cargo-generate-lockfile; args={:?}", env::args().collect::<Vec<_>>());
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
 
     let ws = try!(Workspace::new(&root, config));
index d3f49db6cdec48b071245ae25aaf7d618ee810dd..e67844cce573cd8a1e130b78e688a9d165999385 100644 (file)
@@ -9,6 +9,8 @@ pub struct Options {
     flag_verbose: u32,
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -23,12 +25,16 @@ Options:
     -v, --verbose ...        Use verbose output
     -q, --quiet              No output printed to stdout
     --color WHEN             Coloring: auto, always, never
+    --frozen                 Require Cargo.lock and cache are up to date
+    --locked                 Require Cargo.lock is up to date
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let Options { flag_url: url, flag_reference: reference, .. } = options;
 
     let url = try!(url.to_url().map_err(|e| {
index 3f02f057f3acf170164529aabf9e735bdf91f49d..a779ec7e148b7d95ce40c1202e2beee4cb8b4d84 100644 (file)
@@ -12,6 +12,8 @@ pub struct Options {
     arg_path: Option<String>,
     flag_name: Option<String>,
     flag_vcs: Option<ops::VersionControl>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -31,13 +33,17 @@ Options:
     -v, --verbose ...   Use verbose output
     -q, --quiet         No output printed to stdout
     --color WHEN        Coloring: auto, always, never
+    --frozen            Require Cargo.lock and cache are up to date
+    --locked            Require Cargo.lock is up to date
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
     debug!("executing; cmd=cargo-init; args={:?}", env::args().collect::<Vec<_>>());
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let Options { flag_bin, arg_path, flag_name, flag_vcs, .. } = options;
 
index 7f9ed95195b05798a0477661f41aa1d116c83dd2..78d8f58fd59a399adddcbba1ce4e8d5991299a7c 100644 (file)
@@ -16,6 +16,8 @@ pub struct Options {
     flag_root: Option<String>,
     flag_list: bool,
     flag_force: bool,
+    flag_frozen: bool,
+    flag_locked: bool,
 
     arg_crate: Option<String>,
     flag_vers: Option<String>,
@@ -56,6 +58,8 @@ Build and install options:
     -v, --verbose ...         Use verbose output
     -q, --quiet               Less output printed to stdout
     --color WHEN              Coloring: auto, always, never
+    --frozen                  Require Cargo.lock and cache are up to date
+    --locked                  Require Cargo.lock is up to date
 
 This command manages Cargo's local set of installed binary crates. Only packages
 which have [[bin]] targets can be installed, and all binaries are installed into
@@ -89,9 +93,11 @@ The `--list` option will list all installed packages (and their versions).
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let compile_opts = ops::CompileOptions {
         config: config,
index 50d8249be7fa2e522972b82f7c0ae7e178c4e3f9..635321c578d34162ff77636730d98695210f0cf0 100644 (file)
@@ -13,6 +13,8 @@ pub struct Options {
     flag_verbose: u32,
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -27,13 +29,17 @@ Options:
     -v, --verbose ...        Use verbose output
     -q, --quiet              No output printed to stdout
     --color WHEN             Coloring: auto, always, never
+    --frozen                 Require Cargo.lock and cache are up to date
+    --locked                 Require Cargo.lock is up to date
 
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let token = match options.arg_token.clone() {
         Some(token) => token,
         None => {
index d8a9f1fe5db91cecf7eb1215ec60a4d9802efb12..d5c2d09056ed7ac32d4b14ea01c92d4b965d51a5 100644 (file)
@@ -13,6 +13,8 @@ pub struct Options {
     flag_no_deps: bool,
     flag_quiet: Option<bool>,
     flag_verbose: u32,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -34,12 +36,16 @@ Options:
     -v, --verbose ...          Use verbose output
     -q, --quiet                No output printed to stdout
     --color WHEN               Coloring: auto, always, never
+    --frozen                   Require Cargo.lock and cache are up to date
+    --locked                   Require Cargo.lock is up to date
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<ExportInfo>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let manifest = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
 
     let options = OutputMetadataOptions {
index 70f9018e497da257d5830c5ded7ac66138635ca2..e90194f1d66a3bb11a469847e099b58158e2ff9d 100644 (file)
@@ -12,6 +12,8 @@ pub struct Options {
     arg_path: String,
     flag_name: Option<String>,
     flag_vcs: Option<ops::VersionControl>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -31,13 +33,17 @@ Options:
     -v, --verbose ...   Use verbose output
     -q, --quiet         No output printed to stdout
     --color WHEN        Coloring: auto, always, never
+    --frozen            Require Cargo.lock and cache are up to date
+    --locked            Require Cargo.lock is up to date
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
     debug!("executing; cmd=cargo-new; args={:?}", env::args().collect::<Vec<_>>());
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let Options { flag_bin, arg_path, flag_name, flag_vcs, .. } = options;
 
index 1eb0242957631b802d06228fdad3fecfc08d6073..9b666adfe87e721c08e81f4de44ebbe7a1b7eb71 100644 (file)
@@ -12,6 +12,8 @@ pub struct Options {
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
     flag_list: bool,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -30,6 +32,8 @@ Options:
     -v, --verbose ...        Use verbose output
     -q, --quiet              No output printed to stdout
     --color WHEN             Coloring: auto, always, never
+    --frozen                 Require Cargo.lock and cache are up to date
+    --locked                 Require Cargo.lock is up to date
 
 This command will modify the owners for a package on the specified registry (or
 default). Note that owners of a package can upload new versions, yank old
@@ -41,9 +45,11 @@ and troubleshooting.
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let opts = ops::OwnersOptions {
         krate: options.arg_crate,
         token: options.flag_token,
index 4a45408540919f209f33003cf3811d8ab687918f..40eb7bac77803f77920567b87bb2f4bb0d80d959 100644 (file)
@@ -14,6 +14,8 @@ pub struct Options {
     flag_list: bool,
     flag_allow_dirty: bool,
     flag_jobs: Option<u32>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -33,12 +35,16 @@ Options:
     -v, --verbose ...       Use verbose output
     -q, --quiet             No output printed to stdout
     --color WHEN            Coloring: auto, always, never
+    --frozen                Require Cargo.lock and cache are up to date
+    --locked                Require Cargo.lock is up to date
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
     let ws = try!(Workspace::new(&root, config));
     try!(ops::package(&ws, &ops::PackageOpts {
index 963caf11f046fb72fcc78fcc9d537e812f333eef..13aedf257a77537d60b91e516fa25e4af9a427c5 100644 (file)
@@ -9,6 +9,8 @@ pub struct Options {
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
     flag_manifest_path: Option<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
     arg_spec: Option<String>,
 }
 
@@ -24,6 +26,8 @@ Options:
     -v, --verbose ...        Use verbose output
     -q, --quiet              No output printed to stdout
     --color WHEN             Coloring: auto, always, never
+    --frozen                 Require Cargo.lock and cache are up to date
+    --locked                 Require Cargo.lock is up to date
 
 Given a <spec> argument, print out the fully qualified package id specifier.
 This command will generate an error if <spec> is ambiguous as to which package
@@ -48,9 +52,11 @@ Example Package IDs
 
 pub fn execute(options: Options,
                config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path.clone(), config.cwd()));
     let ws = try!(Workspace::new(&root, config));
 
index f5a9d82776722a63ed7d7ca57756ae1773a6fcea..7c27704600688a11b2cb8643482ff65222c4df64 100644 (file)
@@ -15,6 +15,8 @@ pub struct Options {
     flag_allow_dirty: bool,
     flag_jobs: Option<u32>,
     flag_dry_run: bool,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -35,13 +37,17 @@ Options:
     -v, --verbose ...        Use verbose output
     -q, --quiet              No output printed to stdout
     --color WHEN             Coloring: auto, always, never
+    --frozen                 Require Cargo.lock and cache are up to date
+    --locked                 Require Cargo.lock is up to date
 
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let Options {
         flag_token: token,
         flag_host: host,
index 378e3dc240037c5c0942f7edfe1590de1391ef9e..b889087d6656329cdda5e94c88b7c88c8f0f84fe 100644 (file)
@@ -16,6 +16,8 @@ pub struct Options {
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
     flag_release: bool,
+    flag_frozen: bool,
+    flag_locked: bool,
     arg_args: Vec<String>,
 }
 
@@ -38,6 +40,8 @@ Options:
     -v, --verbose ...       Use verbose output
     -q, --quiet             No output printed to stdout
     --color WHEN            Coloring: auto, always, never
+    --frozen                Require Cargo.lock and cache are up to date
+    --locked                Require Cargo.lock is up to date
 
 If neither `--bin` nor `--example` are given, then if the project only has one
 bin target it will be run. Otherwise `--bin` specifies the bin target to run,
@@ -50,9 +54,11 @@ the ones before go to Cargo.
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
 
index cce7a12d86924c28e332ca45a468b3099e9e3947..10fd9fc9130751df6bda25c875b344bfc3130526 100644 (file)
@@ -25,6 +25,8 @@ pub struct Options {
     flag_test: Vec<String>,
     flag_bench: Vec<String>,
     flag_profile: Option<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -51,6 +53,8 @@ Options:
     -v, --verbose ...        Use verbose output
     -q, --quiet              No output printed to stdout
     --color WHEN             Coloring: auto, always, never
+    --frozen                 Require Cargo.lock and cache are up to date
+    --locked                 Require Cargo.lock is up to date
 
 The specified target for the current package (or package specified by SPEC if
 provided) will be compiled along with all of its dependencies. The specified
@@ -69,9 +73,11 @@ processes spawned by Cargo, use the $RUSTFLAGS environment variable or the
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
     debug!("executing; cmd=cargo-rustc; args={:?}",
            env::args().collect::<Vec<_>>());
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path,
                                               config.cwd()));
index c5710a184c3b0f4ecafe11f5ae89724768546812..010b003c58dbbfc36808ee375f9aa0e8e0bfb8bd 100644 (file)
@@ -22,6 +22,8 @@ pub struct Options {
     flag_example: Vec<String>,
     flag_test: Vec<String>,
     flag_bench: Vec<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -48,6 +50,8 @@ Options:
     -v, --verbose ...        Use verbose output
     -q, --quiet              No output printed to stdout
     --color WHEN             Coloring: auto, always, never
+    --frozen                 Require Cargo.lock and cache are up to date
+    --locked                 Require Cargo.lock is up to date
 
 The specified target for the current package (or package specified by SPEC if
 provided) will be documented with the specified <opts>... being passed to the
@@ -63,9 +67,11 @@ the `cargo help pkgid` command.
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path,
                                               config.cwd()));
index 4d1f1ea3bf13361e77df5fbd94ec8a1abd207748..829039aaa0ef014da6236a07b86dc505d9753e5c 100644 (file)
@@ -10,7 +10,9 @@ pub struct Options {
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
     flag_limit: Option<u32>,
-    arg_query: Vec<String>
+    flag_frozen: bool,
+    flag_locked: bool,
+    arg_query: Vec<String>,
 }
 
 pub const USAGE: &'static str = "
@@ -27,12 +29,16 @@ Options:
     -q, --quiet              No output printed to stdout
     --color WHEN             Coloring: auto, always, never
     --limit LIMIT            Limit the number of results (default: 10, max: 100)
+    --frozen                 Require Cargo.lock and cache are up to date
+    --locked                 Require Cargo.lock is up to date
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let Options {
         flag_host: host,
         flag_limit: limit,
index f7f53bc4bfdb4efb8f38eadff5419a0be91105a4..cd823a59172b3a84ef9c3b1c5702ffe9e2d6e5f6 100644 (file)
@@ -24,6 +24,8 @@ pub struct Options {
     flag_color: Option<String>,
     flag_release: bool,
     flag_no_fail_fast: bool,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -52,6 +54,8 @@ Options:
     -q, --quiet                  No output printed to stdout
     --color WHEN                 Coloring: auto, always, never
     --no-fail-fast               Run all tests regardless of failure
+    --frozen                     Require Cargo.lock and cache are up to date
+    --locked                     Require Cargo.lock is up to date
 
 All of the trailing arguments are passed to the test binaries generated for
 filtering tests and generally providing options configuring how they run. For
@@ -81,9 +85,11 @@ To get the list of all options available for the test binaries use this:
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
 
     let empty = Vec::new();
index 046997a44fb860c44cdae55693e70388a484c8a5..001abde41ef3137240cb7396ada4f246bd28f3a6 100644 (file)
@@ -8,6 +8,8 @@ pub struct Options {
     flag_verbose: u32,
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
 
     arg_spec: String,
 }
@@ -26,6 +28,8 @@ Options:
     -v, --verbose ...         Use verbose output
     -q, --quiet               Less output printed to stdout
     --color WHEN              Coloring: auto, always, never
+    --frozen                  Require Cargo.lock and cache are up to date
+    --locked                  Require Cargo.lock is up to date
 
 The argument SPEC is a package id specification (see `cargo help pkgid`) to
 specify which crate should be uninstalled. By default all binaries are
@@ -34,9 +38,11 @@ only uninstall particular binaries.
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
 
     let root = options.flag_root.as_ref().map(|s| &s[..]);
     try!(ops::uninstall(root, &options.arg_spec, &options.flag_bin, config));
index 8c72dd1118dc6809a2528f84c698a1ce541cd8d3..6d1d7935b9c1edf4ccc9f8ff070e34b47a07a076 100644 (file)
@@ -14,6 +14,8 @@ pub struct Options {
     flag_verbose: u32,
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -31,6 +33,8 @@ Options:
     -v, --verbose ...            Use verbose output
     -q, --quiet                  No output printed to stdout
     --color WHEN                 Coloring: auto, always, never
+    --frozen                     Require Cargo.lock and cache are up to date
+    --locked                     Require Cargo.lock is up to date
 
 This command requires that a `Cargo.lock` already exists as generated by
 `cargo build` or related commands.
@@ -55,9 +59,11 @@ For more information about package id specifications, see `cargo help pkgid`.
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
     debug!("executing; cmd=cargo-update; args={:?}", env::args().collect::<Vec<_>>());
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd()));
 
     let update_opts = ops::UpdateOptions {
index 0ce407e08c4783560a61b81096c9509c97a123b0..27424f7a6813f3b561361b22c3cba0f794019235 100644 (file)
@@ -16,6 +16,8 @@ pub struct Flags {
     flag_verbose: u32,
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub const USAGE: &'static str = "
@@ -31,12 +33,16 @@ Options:
     -v, --verbose ...       Use verbose output
     -q, --quiet             No output printed to stdout
     --color WHEN            Coloring: auto, always, never
+    --frozen                Require Cargo.lock and cache are up to date
+    --locked                Require Cargo.lock is up to date
 ";
 
 pub fn execute(args: Flags, config: &Config) -> CliResult<Option<Error>> {
-    try!(config.configure_shell(args.flag_verbose,
-                                args.flag_quiet,
-                                &args.flag_color));
+    try!(config.configure(args.flag_verbose,
+                          args.flag_quiet,
+                          &args.flag_color,
+                          args.flag_frozen,
+                          args.flag_locked));
 
     let mut contents = String::new();
     let filename = args.flag_manifest_path.unwrap_or("Cargo.toml".into());
index a869f36fffcb1b5ac9cd78ef1fea584fe40cea25..7971efbb37e2e6c44f6480e02bdb52c5e69fd9fa 100644 (file)
@@ -11,6 +11,8 @@ pub struct Options {
     flag_quiet: Option<bool>,
     flag_color: Option<String>,
     flag_undo: bool,
+    flag_frozen: bool,
+    flag_locked: bool,
 }
 
 pub static USAGE: &'static str = "
@@ -28,6 +30,8 @@ Options:
     -v, --verbose ...   Use verbose output
     -q, --quiet         No output printed to stdout
     --color WHEN        Coloring: auto, always, never
+    --frozen            Require Cargo.lock and cache are up to date
+    --locked            Require Cargo.lock is up to date
 
 The yank command removes a previously pushed crate's version from the server's
 index. This command does not delete any data, and the crate will still be
@@ -39,9 +43,11 @@ crates to be locked to any yanked version.
 ";
 
 pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
-    try!(config.configure_shell(options.flag_verbose,
-                                options.flag_quiet,
-                                &options.flag_color));
+    try!(config.configure(options.flag_verbose,
+                          options.flag_quiet,
+                          &options.flag_color,
+                          options.flag_frozen,
+                          options.flag_locked));
     try!(ops::yank(config,
                    options.arg_crate,
                    options.flag_vers,
index 1ecf4406d44024cb7f3e938c7d12815741b94411..ccfe87cabee5e61ba968de21cae3d95ec8e5b8f4 100644 (file)
@@ -269,7 +269,10 @@ impl<'cfg> Registry for PackageRegistry<'cfg> {
 
         let ret = if overrides.is_empty() {
             // Ensure the requested source_id is loaded
-            try!(self.ensure_loaded(dep.source_id(), Kind::Normal));
+            try!(self.ensure_loaded(dep.source_id(), Kind::Normal).chain_error(|| {
+                human(format!("failed to load source for a dependency \
+                               on `{}`", dep.name()))
+            }));
 
             match self.sources.get_mut(dep.source_id()) {
                 Some(src) => try!(src.query(&dep)),
index f0a1f72c31253728fb91eea7947434c05c9de950..91a2bf2d7a051053c590e32e04366c4aeec89051 100644 (file)
@@ -86,6 +86,12 @@ pub fn write_pkg_lockfile(ws: &Workspace, resolve: &Resolve) -> CargoResult<()>
         }
     }
 
+    if !ws.config().lock_update_allowed() {
+        let flag = if ws.config().network_allowed() {"--frozen"} else {"--locked"};
+        bail!("the lock file needs to be updated but {} was passed to \
+               prevent this", flag);
+    }
+
     // Ok, if that didn't work just write it out
     root.open_rw("Cargo.lock", ws.config(), "Cargo.lock file").and_then(|mut f| {
         try!(f.file().set_len(0));
index ac831b3576aa3878d126ce4ad5611ac159fdd50d..e0d4fd5d6e6f396ce366397506ad79cc7e2e86bd 100644 (file)
@@ -182,6 +182,11 @@ pub fn registry(config: &Config,
 
 /// Create a new HTTP handle with appropriate global configuration for cargo.
 pub fn http_handle(config: &Config) -> CargoResult<Easy> {
+    if !config.network_allowed() {
+        bail!("attempting to make an HTTP request, but --frozen was \
+               specified")
+    }
+
     // The timeout option for libcurl by default times out the entire transfer,
     // but we probably don't want this. Instead we only set timeouts for the
     // connect phase as well as a "low speed" timeout so if we don't receive
index 7ffdddade840031f9f733271a3bdd32f63399a80..1149bfffd02cd7a301dc35e5847f09f99e88a7dd 100644 (file)
@@ -560,19 +560,26 @@ fn with_authentication<T, F>(url: &str, cfg: &git2::Config, mut f: F)
     })
 }
 
-pub fn fetch(repo: &git2::Repository, url: &str,
-             refspec: &str, cargo_config: &Config) -> CargoResult<()> {
-    // Create a local anonymous remote in the repository to fetch the url
+pub fn fetch(repo: &git2::Repository,
+             url: &str,
+             refspec: &str,
+             config: &Config) -> CargoResult<()> {
+    if !config.network_allowed() {
+        bail!("attempting to update a git repository, but --frozen \
+               was specified")
+    }
 
     with_authentication(url, &try!(repo.config()), |f| {
         let mut cb = git2::RemoteCallbacks::new();
         cb.credentials(f);
+
+        // Create a local anonymous remote in the repository to fetch the url
         let mut remote = try!(repo.remote_anonymous(&url));
         let mut opts = git2::FetchOptions::new();
         opts.remote_callbacks(cb)
             .download_tags(git2::AutotagOption::All);
 
-        try!(network::with_retry(cargo_config, ||{
+        try!(network::with_retry(config, ||{
             remote.fetch(&[refspec], Some(&mut opts), None)
         }));
         Ok(())
index 06e6344bb96ef5087892d8d18472bc4c62f92e40..f89f6bae794a19ed4749d7b9e680c365a9a1cce1 100644 (file)
@@ -177,6 +177,7 @@ use core::dependency::{Dependency, DependencyInner, Kind};
 use sources::{PathSource, git};
 use util::{CargoResult, Config, internal, ChainError, ToUrl, human};
 use util::{hex, Sha256, paths, Filesystem, FileLock};
+use util::network;
 use ops;
 
 const DEFAULT: &'static str = "https://github.com/rust-lang/crates.io-index";
@@ -315,7 +316,9 @@ impl<'cfg> RegistrySource<'cfg> {
                 body.extend_from_slice(buf);
                 Ok(buf.len())
             }));
-            try!(handle.perform());
+            try!(network::with_retry(self.config, || {
+                handle.perform()
+            }))
         }
         let code = try!(handle.response_code());
         if code != 200 && code != 0 {
@@ -495,7 +498,7 @@ impl<'cfg> RegistrySource<'cfg> {
         let refspec = "refs/heads/*:refs/remotes/origin/*";
 
         try!(git::fetch(&repo, &url, refspec, &self.config).chain_error(|| {
-            internal(format!("failed to fetch `{}`", url))
+            human(format!("failed to fetch `{}`", url))
         }));
 
         // git reset --hard origin/master
index 37bdf0357361ef5a67dc18cfa2b7b4fefbb46a8f..d1b299e5f4684d67f59d537b2531b368f9da6dc4 100644 (file)
@@ -32,6 +32,8 @@ pub struct Config {
     rustdoc: PathBuf,
     target_dir: RefCell<Option<Filesystem>>,
     extra_verbose: Cell<bool>,
+    frozen: Cell<bool>,
+    locked: Cell<bool>,
 }
 
 impl Config {
@@ -49,6 +51,8 @@ impl Config {
             rustdoc: PathBuf::from("rustdoc"),
             target_dir: RefCell::new(None),
             extra_verbose: Cell::new(false),
+            frozen: Cell::new(false),
+            locked: Cell::new(false),
         };
 
         try!(cfg.scrape_tool_config());
@@ -292,10 +296,12 @@ impl Config {
         })
     }
 
-    pub fn configure_shell(&self,
-                           verbose: u32,
-                           quiet: Option<bool>,
-                           color: &Option<String>) -> CargoResult<()> {
+    pub fn configure(&self,
+                     verbose: u32,
+                     quiet: Option<bool>,
+                     color: &Option<String>,
+                     frozen: bool,
+                     locked: bool) -> CargoResult<()> {
         let extra_verbose = verbose >= 2;
         let verbose = if verbose == 0 {None} else {Some(true)};
         let cfg_verbose = try!(self.get_bool("term.verbose")).map(|v| v.val);
@@ -329,6 +335,8 @@ impl Config {
         self.shell().set_verbosity(verbosity);
         try!(self.shell().set_color_config(color.map(|s| &s[..])));
         self.extra_verbose.set(extra_verbose);
+        self.frozen.set(frozen);
+        self.locked.set(locked);
 
         Ok(())
     }
@@ -337,6 +345,14 @@ impl Config {
         self.extra_verbose.get()
     }
 
+    pub fn network_allowed(&self) -> bool {
+        !self.frozen.get()
+    }
+
+    pub fn lock_update_allowed(&self) -> bool {
+        !self.frozen.get() && !self.locked.get()
+    }
+
     fn load_values(&self) -> CargoResult<()> {
         let mut cfg = CV::Table(HashMap::new(), PathBuf::from("."));
 
index ae7e9bcaa268493c64406cfc34fbd4b16f151797..7782247ce799ab03719eef42e77211de7192c973 100644 (file)
@@ -155,3 +155,37 @@ many possible names has historically led to confusion where one case was handled
 but others were accidentally forgotten.
 
 [crates.io]: https://crates.io/
+
+# How can Cargo work offline?
+
+Cargo is often used in situations with limited or no network access such as
+airplanes, CI environments, or embedded in large production deployments. Users
+are often surprised when Cargo attempts to fetch resources from the network, and
+hence the request for Cargo to work offline comes up frequently.
+
+Cargo, at its heart, will not attempt to access the network unless told to do
+so. That is, if no crates comes from crates.io, a git repository, or some other
+network location, Cargo will never attempt to make a network connection. As a
+result, if Cargo attempts to touch the network, then it's because it needs to
+fetch a required resource.
+
+Cargo is also quite aggressive about caching information to minimize the amount
+of network activity. It will guarantee, for example, that if `cargo build` (or
+an equivalent) is run to completion then the next `cargo build` is guaranteed to
+not touch the network so long as `Cargo.toml` has not been modified in the
+meantime. This avoidance of the network boils down to a `Cargo.lock` existing
+and a populated cache of the crates reflected in the lock file. If either of
+these components are missing, then they're required for the build to succeed and
+must be fetched remotely.
+
+As of Rust 1.11.0 (to be released 2016-09-29) Cargo understands a new flag,
+`--frozen`, which is an assertion that it shouldn't touch the network. When
+passed, Cargo will immediately return an error if it would otherwise attempt a
+network request. The error should include contextual information about why the
+network request is being made in the first place to help debug as well. Note
+that this flag *does not change the behavior of Cargo*, it simply asserts that
+Cargo shouldn't touch the network as a previous command has been run to ensure
+that network activity shouldn't be necessary.
+
+Note that Cargo does not yet support vendoring in a first-class fashion, but
+this is a hotly desired feature and coming soon!
index 880ba85ba32a1fb8353056e6baad0b285a949e97..3b806ef463a36972b78711cf2f80d6b04e2b7e74 100644 (file)
@@ -73,9 +73,10 @@ fn bad3() {
             [http]
               proxy = true
         "#);
+    Package::new("foo", "1.0.0").publish();
     assert_that(foo.cargo_process("publish").arg("-v"),
                 execs().with_status(101).with_stderr("\
-[UPDATING] registry `https://[..]`
+[UPDATING] registry `[..]`
 [ERROR] invalid configuration for key `http.proxy`
 expected a string, but found a boolean in [..]config
 "));
@@ -246,7 +247,10 @@ fn bad_git_dependency() {
     assert_that(foo.cargo_process("build").arg("-v"),
                 execs().with_status(101).with_stderr("\
 [UPDATING] git repository `file:///`
-[ERROR] Unable to update file:///
+[ERROR] failed to load source for a dependency on `foo`
+
+Caused by:
+  Unable to update file:///
 
 Caused by:
   failed to clone into: [..]
index 6ac2107df7c3dbb784a96d69bf04de74634ca79d..8784329a9d6663cef8ffe1deb17a38729dc2a32d 100644 (file)
@@ -102,7 +102,10 @@ fn http_auth_offered() {
     assert_that(p.cargo_process("build"),
                 execs().with_status(101).with_stderr(&format!("\
 [UPDATING] git repository `http://{addr}/foo/bar`
-[ERROR] Unable to update http://{addr}/foo/bar
+[ERROR] failed to load source for a dependency on `bar`
+
+Caused by:
+  Unable to update http://{addr}/foo/bar
 
 Caused by:
   failed to clone into: [..]
index 46f118a44574f3cdccb5af395f4ab19f808d95c6..7157bb5f183cd1c607ce450be22b8961b6381448 100644 (file)
@@ -467,7 +467,10 @@ fn override_with_nothing() {
                 execs().with_status(101).with_stderr("\
 [UPDATING] registry [..]
 [UPDATING] git repository [..]
-error: Unable to update file://[..]
+[ERROR] failed to load source for a dependency on `foo`
+
+Caused by:
+  Unable to update file://[..]
 
 Caused by:
   Could not find Cargo.toml in `[..]`
index 574851e93877f75a58f0b600d64ecb7bed21d4fb..0e8aa25c910554c0135523ef90ff9220bfc8783c 100644 (file)
@@ -524,7 +524,10 @@ fn error_message_for_missing_manifest() {
     assert_that(p.cargo_process("build"),
                 execs().with_status(101)
                        .with_stderr("\
-[ERROR] Unable to update file://[..]
+[ERROR] failed to load source for a dependency on `bar`
+
+Caused by:
+  Unable to update file://[..]
 
 Caused by:
   failed to read `[..]bar[..]Cargo.toml`
index 7f600fb17862a3abc83921fcc817632380ed577c..1a2371bfdb6065dde4886b198548176329428ce6 100644 (file)
@@ -1070,3 +1070,34 @@ fn upstream_warnings_on_extra_verbose() {
 [..]warning: function is never used[..]
 "));
 }
+
+#[test]
+fn disallow_network() {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [project]
+            name = "bar"
+            version = "0.5.0"
+            authors = []
+
+            [dependencies]
+            foo = "*"
+        "#)
+        .file("src/main.rs", "fn main() {}");
+    p.build();
+
+    assert_that(p.cargo("build").arg("--frozen"),
+                execs().with_status(101).with_stderr("\
+[UPDATING] registry `[..]`
+error: failed to load source for a dependency on `foo`
+
+Caused by:
+  Unable to update registry [..]
+
+Caused by:
+  failed to fetch `[..]`
+
+Caused by:
+  attempting to update a git repository, but --frozen was specified
+"));
+}